package scheduler.fixtures;

import fitlibrary.DoFixture;
import fit.Fixture;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.ejb.CreateException;
import javax.ejb.EJBContext;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import se392.ateam2006.authentication.GroupMgmtRemote;
import se392.ateam2006.meetingmgmt.MeetingMgmtRemote;
import se392.ateam2006.meetingmgmt.meeting.MeetingEntity;
import se392.ateam2006.resourcemgmt.ResourceMgmtRemote;
import se392.ateam2006.resourcemgmt.participant.ParticipationEntity;
import se392.ateam2006.resourcemgmt.participant.exclusionset.ExclusionRangeEntity;
import se392.ateam2006.user.UserEntity;
import se392.ateam2006.user.UserMgmtRemote;
import se392.ateam2006.utils.SystemUtils;

/**
 * Main Fitnesse class.
 * This class acts as the contact point for most of the operations
 * in Fitnesse.
 * @author Ateam (Matthew Bennett, Claire Melton, Shingai Manyiwa, John Adderley)
 * @version 25/03/07
 */
public class StartApplication extends DoFixture {

    //private ManagementRemoteHome home;
    private MeetingMgmtRemote meetingManage;
    private ResourceMgmtRemote resourceManage;
    private UserMgmtRemote userManage;
    private GroupMgmtRemote groupManage;

    /*
     * Adding this means that the fitness class can be started as a normal Executable.
     */
    public static void Main(String[] args) {
        StartApplication start = new StartApplication();

    }

    /**
     * Creates a new instance of StartApplication.
     * Sets up a connection between the fitnesse tables and the application
     * server.
     */
    public StartApplication() {

        System.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
        System.setProperty("org.omg.CORBA.ORBInitialPort", "3700");

        try {
            InitialContext jndicontext = new InitialContext();
            meetingManage = (MeetingMgmtRemote) jndicontext.lookup("se392.ateam2006.meetingmgmt.MeetingMgmtRemote");

            resourceManage = (ResourceMgmtRemote) jndicontext.lookup("se392.ateam2006.resourcemgmt.ResourceMgmtRemote");

            userManage = (UserMgmtRemote) jndicontext.lookup("se392.ateam2006.user.UserMgmtRemote");

            groupManage = (GroupMgmtRemote) jndicontext.lookup("se392.ateam2006.authentication.GroupMgmtRemote");
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        resourceManage.setTestingMode(true);

    }

    public Fixture setUpVenues() {
        return new SetUpVenues(resourceManage);
    }

    public Fixture setUpVenueOwnership() {
        return new SetUpVenueOwnership(resourceManage);
    }

    public Fixture setUpEquipment() {
        return new SetUpEquipment(resourceManage);
    }

    public Fixture setUpEquipmentOwnership() {
        return new SetUpEquipmentOwnership(resourceManage);
    }

    public Fixture setUpEmails() {
        return new SetUpEmails(userManage);
    }

    /**
     * Sets the "Current" time. 
     * Whenever the system requests the current time, a faked time should
     * be returned corresponding to the string last entered into this
     * method.
     */
    public void timeIsNow(String time) {

        String[] dateTime = time.split(" ");
        String[] startDateArray = dateTime[0].split("/");
        String[] startTimeArray = dateTime[1].split(":");
        Calendar start = Calendar.getInstance();
        start.set(Integer.parseInt(startDateArray[0]),
                (Integer.parseInt(startDateArray[1]) - 1), // Jan starts at 0!
                Integer.parseInt(startDateArray[2]),
                Integer.parseInt(startTimeArray[0]),
                Integer.parseInt(startTimeArray[1]));
        start.set(Calendar.SECOND, 0);
        start.set(Calendar.MILLISECOND, 0);

        System.out.println("MANUTIME: String = " + time + ", date says " + start.getTime());
        resourceManage.setTestDate(start.getTime());
    //return false;
    }

    public Fixture createMeeting() {
        return new CreateMeeting(meetingManage, resourceManage, userManage);
    }

    public Fixture participantsForMeeting(String meetingId) {
        return new ParticipantsForMeeting(resourceManage, meetingManage, meetingId);
    }

    //TODO: must refactor
    public boolean submitExclusionSetForParticipantForMeetingWithStartDateAndEndDate(String email,
            String meetingID,
            String startDate,
            String endDate) throws Exception {

        UserEntity user = userManage.getUserByID(email);
        MeetingEntity meeting = meetingManage.findMeetingById(meetingID);

        //ParticipationEntity pe = resourceManage.getParticipant(user, meeting);

        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd kk:mm");
        GregorianCalendar startDateCal = new GregorianCalendar();
        if (startDate.equals("") && endDate.equals("")) {
            ExclusionRangeEntity ere = null;
            ere = resourceManage.createExclusionRangeEntity(user, meeting, false);
            return true;
        }
        try {
            startDateCal.setTime(format.parse(startDate));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }


        GregorianCalendar endDateCal = new GregorianCalendar();
        try {
            endDateCal.setTime(format.parse(endDate));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        ExclusionRangeEntity ere = null;

        //try {
        ere = resourceManage.createExclusionRangeEntity(user, meeting, startDateCal, endDateCal, false);
        //} catch (CreateException e) {
        //    System.out.println("Failed to create Exclusion range: " + e.getMessage() +
        //            "\nMStart: \t" + meeting.getStartDateRange().getTime() +
        //            " MEnd: \t" + meeting.getEndDateRange().getTime() +
        //            "\nExcStart: \t" + startDateCal.getTime() +
        //            " ExcEnd: \t" + endDateCal.getTime());
        //    e.printStackTrace();
        // }

        Collection<ExclusionRangeEntity> participations = resourceManage.getExclusionSetsForParticipant(user);

        if (participations.contains(ere)) {
            return true;
        } else {

            return false;
        }

    //pe.
    //SubmitResponse sr =  new SubmitResponse(manage, email, meetingID, startDate, endDate);
    //return sr.submitResponseWithExclsuionSets();
    }

    //TODO: must refactor
    public boolean submitPreferenceSetForParticipantForMeetingWithStartDateAndEndDate(String email,
            String meetingID,
            String startDate,
            String endDate) {

        UserEntity user = userManage.getUserByID(email);
        MeetingEntity meeting = meetingManage.findMeetingById(meetingID);


        ParticipationEntity pe = resourceManage.getParticipant(user, meeting);

        String[] startDateTime = startDate.split(" ");
        String[] endDateTime = endDate.split(" ");
        String[] startDateArray = startDateTime[0].split("/");
        String[] startTimeArray = startDateTime[1].split(":");
        String[] endDateArray = endDateTime[0].split("/");
        String[] endTimeArray = endDateTime[1].split(":");
        Calendar start = Calendar.getInstance();
        start.set(Integer.parseInt(startDateArray[0]),
                (Integer.parseInt(startDateArray[1]) - 1), // Jan starts at 0!
                Integer.parseInt(startDateArray[2]),
                Integer.parseInt(startTimeArray[0]),
                Integer.parseInt(startTimeArray[1]));
        Calendar end = Calendar.getInstance();
        end.set(Integer.parseInt(endDateArray[0]),
                (Integer.parseInt(endDateArray[1]) - 1), // Jan starts at 0!
                Integer.parseInt(endDateArray[2]),
                Integer.parseInt(endTimeArray[0]),
                Integer.parseInt(endTimeArray[1]));
        start.set(Calendar.SECOND, 0);
        end.set(Calendar.SECOND, 0);
        start.set(Calendar.MILLISECOND, 0);
        end.set(Calendar.MILLISECOND, 0);


        ExclusionRangeEntity ere = null;

        try {
            ere = resourceManage.createExclusionRangeEntity(user, meeting, start, end, true);
        } catch (CreateException e) {
            System.out.println("Failed to create Preference set: " + e.getMessage() +
                    "\nMStart: \t" + meeting.getStartDateRange().getTime() +
                    " MEnd: \t" + meeting.getEndDateRange().getTime() +
                    "\nPrefStart: \t" + start.getTime() +
                    " PrefEnd: \t" + end.getTime());
            e.printStackTrace();
        }

        Collection<ExclusionRangeEntity> participations = resourceManage.getExclusionSetsForParticipant(user);

        if (participations.contains(ere)) {
            return true;
        } else {

            return false;
        }

    //pe.
    //SubmitResponse sr =  new SubmitResponse(manage, email, meetingID, startDate, endDate);
    //return sr.submitResponseWithExclsuionSets();
    }

    /*
    public boolean submitPreferenceSetForParticipantForMeetingWithStartDateAndEndDate(String email,
    String meetingID,
    String startDate,
    String endDate){
    //SubmitResponse sr =  new SubmitResponse(manage, email, meetingID, startDate, endDate);
    //return sr.submitResponseWithPreferenceSets();
    }
     */
    public void addParticipantTo(String status, String userId, String meetingId) throws Exception {
        boolean theStatus = false;

        if (status.equals("active")) {
            theStatus = true;
        } else if (status.equals("normal")) {
            theStatus = false;
        } else {
            throw new Exception();
        }
        MeetingEntity meeting = meetingManage.findMeetingById(meetingId);
        if (meeting != null) {
            UserEntity user = userManage.getUserByID(userId);
            if (user != null) {
                ParticipationEntity part = resourceManage.createParticipation(meeting,
                        user, theStatus);
            } else {
                throw new Exception();
            }
        } else {
            throw new Exception();
        }
    }

    public Fixture plannedMeetings() {
        return new PlannedMeetings(meetingManage);
    }

    public void initiatorIdStartDateRangeEndDateRangeDurationTitleDescriptionVenueSize(String initiator, String id, String startDateRange,
            String endDateRange, String duration, String title, String description, String venue, int size) throws Exception {
        CreateMeeting createMeeting = new CreateMeeting(meetingManage, resourceManage, userManage);
        createMeeting.initiatorIdStartDateRangeEndDateRangeDurationTitleDescriptionVenueSize(initiator, id, startDateRange,
                endDateRange, duration, title, description, venue, size);
    }

    public int activeParticipantNumberFor(String id) {
        return resourceManage.getActiveParticipantCount(meetingManage.findMeetingById(id));
    }

    public int allParticipantNumberFor(String id) {
        return resourceManage.getMeetingParticipantCount(meetingManage.findMeetingById(id));
    }

    public boolean removeFrom(String userId, String meetingId) {
        try {

            resourceManage.removeParticipation(
                    resourceManage.getParticipant(
                    userManage.getUserByID(userId), meetingManage.findMeetingById(meetingId)));

            return true;

        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
            return false;
        }

    }

    public Fixture exclusionSetForParticipantForMeeting(String email, String meetingId) {
        return new ExclusionSetForParticipantForMeeting(userManage, meetingManage, resourceManage, email, meetingId);
    }

    public Fixture preferenceSetForParticipantForMeeting(String email, String meetingId) {
        return new PreferenceSetForParticipantForMeeting(userManage, meetingManage, resourceManage, email, meetingId);
    }

    public Fixture exlusionSetForMeeting(String meetingId) {
        return new ExclusionSetForMeeting(meetingManage, resourceManage, meetingId);
    }

    public Fixture preferenceSetForMeeting(String meetingId) {
        return new PreferenceSetForMeeting(meetingManage, resourceManage, meetingId);
    }

    public Fixture preferenceSetForParticipant(String userId) {
        return new PreferenceSetForParticipant(userManage, resourceManage, userId);
    }

    public Fixture exclusionSetForParticipant(String userId) {
        return new ExclusionSetForParticipant(userManage, resourceManage, userId);
    }

    public int meetingCount() {
        int size = -1024;

        try {
            size = meetingManage.getMeetingCount();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return size;
    }

    public Fixture removeAllMeetings() {
        return new RemoveAllMeetings(meetingManage);
    }

    public Fixture removeAllEquipment() {
        return new RemoveAllEquipment(resourceManage);
    }

    public Fixture removeAllVenues() {
        return new RemoveAllVenues(resourceManage);
    }

    public Fixture removeAllUsers() {
        return new RemoveAllUsers(userManage);
    }

    public Fixture removeAllExclusionSets() {
        return new RemoveAllExclusionSets(resourceManage);
    }

//    public Fixture removeAllDefaultMeetingStartTimes(){
//        return new  RemoveAllDefaultMeetingStartTimes(manage);
//    }
//
//    public int defaultMeetingStartTimesCount(){
//        int size = 0;
//        try {
//            size = manage.getDefaultMeetingStartTimesCount();
//        } catch (RemoteException ex) {
//            ex.printStackTrace();
//        }
//
//        return size;
//    }
//
    public int equipmentCount() {
        //TODO: actually implement
        int size = 0;
        return size;
    }

    public int venueCount() {
        return resourceManage.getRoomCount();
    }

    public int userCount() {
        return userManage.getUserCount();
    }

    public int exclusionSetsCount() {
        return resourceManage.getExclusionSetsCount();
    }

    public Fixture setUpBookingPermissions() {
        return new SetUpBookingPermissions(userManage, groupManage);
    }

    public boolean setCutOffPeriodAsDay(int days) {
        try {
            meetingManage.setDefaultCutOffPeriod(days);
            return true;
        } catch (Exception e) {
            System.err.println("failed to setup cutoff period " + e.getMessage());
            return false;
        }
    }
//
    public boolean setWorkingDayStartAndEnd(String startDate, String endDate) {

        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        Date time;

        try {
            time = sdf.parse(startDate);
        } catch (ParseException ex) {
            System.err.println("failed to setup working start and end day " + ex.getMessage());
            return false;
        }

        GregorianCalendar date = new GregorianCalendar();
        date.setTime(time);

        try {
            meetingManage.setDefaultWorkingDayStart(date); //Changed from manage to meetingManage sac4 mcs3
            System.err.println("SAM" + date);
            time = sdf.parse(endDate);
            date = new GregorianCalendar();
            date.setTime(time);

            meetingManage.setDefaultWorkingDayEnd(date); //Changed from manage to meetingManage sac4 mcs3
            return true;

        } catch (Exception e) {
            System.err.println("failed to setup working start and end day " + e.getMessage());
            return false;
        }
    }
    //uncommened this code and added the SystemsUtils class in ejb utils
    //also Clock class, SystemClock class to ejb utils sac4 mcs3
    public boolean setUpWorkingWeekDays(String d) {

        try {
            //String days = SystemUtils.dayStringBuilder(d);
            meetingManage.setWorkingDays(d);
            return true;
        } catch (Exception e) {
            System.err.println("failed setting up working week days " + e.getMessage());
            return false;
        }
    }

    public boolean setUpMeetingStartTimesForPeriodStartTimePeriodEndTimeOffset(String startTime, String endTime, int offset) {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        Date sTime;
        Date eTime;

        try {
            sTime = sdf.parse(startTime);
            eTime = sdf.parse(endTime);
        } catch (ParseException ex) {
            System.err.println("Couldn't parse Time " + ex.getMessage());
            return false;
        }

        GregorianCalendar startDate = new GregorianCalendar();
        startDate.setTime(sTime);
        GregorianCalendar endDate = new GregorianCalendar();
        endDate.setTime(eTime);

        //DefaultMeetingStartTimesDTO dto = new DefaultMeetingStartTimesDTO(startDate, endDate, offset);

        try {
            meetingManage.setMeetingStartPeriods(startDate, endDate, offset);
        } catch (Exception e) {
            System.err.println("error setting meetingStartPeriods" + e.getMessage());
            return false;
        }

        return true;
    }

    /**
     * Not sure if should remove preferences sets too
     * @param meetingID
     * @return
     */
    public boolean removeAllExclusionSetsForMeeting(String meetingID) {
        resourceManage.removeExclusionSetsByMeetingId(meetingID);
        Collection<ExclusionRangeEntity> ex = resourceManage.getExclusionSetsForMeetingId(meetingID);
        if (ex.isEmpty()) {
            return true;
        }
        return false;
    }
//
    public boolean submitEquipmentRequirementForParticipantForMeetingEquipmentTypeNumber(String userId, String meetingId, String equipmentType, int number) {
        return meetingManage.addEquipmentConstraint(userId, meetingId, equipmentType, number);

    }    

    public boolean submitEquipmentConstraintsForParticipantForMeetingEquipmentTypeNumber(String userId, String meetingId, String equipmentType, int number) {
        return meetingManage.addEquipmentConstraint(userId, meetingId, equipmentType, number);
    }
    
    public boolean submitEquipmentRequestForParticipantForMeetingEquipmentTypeNumber(String userId, String meetingId, String equipmentType, int number) {
        return meetingManage.addEquipmentConstraint(userId, meetingId, equipmentType, number);
    }

    public Fixture equipmentConstraintForParticipantForMeeting(String userId, String meetingId) {
        //return new EquipmentConstraintForParticipantForMeeting(meetingManage, userId, meetingId);
        return null;
    }

    public Fixture calculateDateTimeVenueForMeeting(String meetingId) {
        return new CalculateDateTimeVenueForMeeting(meetingManage, meetingId);
    }

    public boolean bookMeetingAtDateTimeVenue(String meetingId, String theStartDate, String venue) {
        return meetingManage.bookTheMeeting(meetingId, venue, theStartDate);
    }

    public Fixture getBookedMeetings() {
        return new GetBookedMeetings(meetingManage);
    }

    public boolean unbookMeeting(String meetingId) {
        return meetingManage.deleteMeetingById(meetingId);
    }

    public boolean removeAllEquipmentRequirementsForMeeting(String meetingID) {
        try {
            meetingManage.removeEquipmentRequirementsForMeeting(meetingID);
            return true;
        } catch (Exception e) {
            System.err.println("failed to remove equipment for meeting" + e.getMessage());
            return false;
        }
    }
}
